iT邦幫忙

2024 iThome 鐵人賽

DAY 2
0
佛心分享-刷題不只是刷題

Leecode刷題系列 第 5

D6:Q24Swap Nodes in Pairs

  • 分享至 

  • xImage
  •  

https://ithelp.ithome.com.tw/upload/images/20240921/20169309uhr5N9GmU4.png
這題要我交換鏈結串列的節點,而且不能改節點內的值,只能用節點之間的連結,解重點是怎麼在不打亂鏈結的結構這個前提下交換,並正確地處理每對相鄰節點的交換過程。

理解題目:
要兩兩交換相鄰節點,且只能調整節點的指向完成交換,不能直接改節點內的值。
特殊情況:鏈結串列可能是空的(head = []),或鏈結串列的節點數是奇數(不能湊成對)如果鏈結串列是空的(head = None)只有一個節點(無法形成一對),直接返回原鏈結串列。
遞歸與迭代的思路:
可以用遞歸處理每對相鄰節點,交換完一對後,用遞歸解決剩下的鏈結串列,或是用迭代,在每對相鄰節點間調整節點指針的方式完成交換操作,並用一個指標(prev)來保持對已處理部分的連結。
交換節點操作:
設有三個指針:prev(指向前一個節點)、first(指向當前第一個節點)、second(指向當前第二個節點),要交換 first 和 second,然後調整 prev 的指向,讓它指向交換後新節點的順序。
然後更新 prev、first 和 second 指針,處理剩下的鏈結串列。

遞歸法:
每次處理當前兩個節點,交換後遞歸處理剩下的節點,基本情況是鏈結串列只剩一個節點或者沒有節點時停止遞歸。
迭代法:
用一個虛擬節點(dummy node)簡化交換頭部節點的操作,逐一交換相鄰節點,並用 prev 指針保持已經處理部分的連續性。

技巧:
熟悉遞歸與迭代的兩種想法。
注意邊界情況(如空鏈結或奇數節點)。

步驟 :
先檢查空鏈結和單節點情況,在處理前,先檢查 head 是不是空或只有一個節點,如果 head 為空或只有一個節點,直接返回 head,因為沒節點可以交換,交換相鄰節點,假設 first_node = head 和 second_node = head.next,要把 second_node 放在 first_node 前面,讓 first_node 的下一個節點連接到後面的節點,再用遞歸或迭代處理後面的鏈結。

程式碼:
#定義單向鏈結串列的節點類別
class ListNode(object):
def init(self, val=0, next=None):
self.val = val
self.next = next

class Solution(object):
def swapPairs(self, head):
"""
:type head: ListNode
:rtype: ListNode
"""
#如果鏈結串列式空或只有一個節點,直接返回
if not head or not head.next:
return head

    #建一個虛擬節點,方便處理頭節點的交換
    dummy = ListNode(0)
    dummy.next = head
    
    #初始化當前節點為虛擬節點
    current = dummy
    
    #迭代處理每一對相鄰節點
    while current.next and current.next.next:
        # 定義兩個要交換的節點
        first = current.next
        second = current.next.next
        
        #交換節點
        first.next = second.next
        second.next = first
        current.next = second
        
        #將指針移動到下一對節點
        current = first
    
    #返回新的頭節點
    return dummy.next

程式碼註解:
虛擬節點(dummy node),簡化操作,尤其是在處理頭節點的交換,創建一個虛擬節點 dummy,用 next 指向 head,就可避免處理頭節點時出現特殊情況。
迭代交換:用 current 來跟蹤當前節點,每次處理兩相鄰節點,並進行交換,步驟是:first 節點指向 second 的下一個節點;
second 節點指向 first;最後將把current 節點的 next 指向 second,就完成了,每次交換後,把 current 指向 first,就可繼續處理下一對相鄰節點,邊界情況,如果鏈結串列的節點數是奇數,最後一個節點就不會被交換,如果是空鏈結或只有一個節點,函數會直接返回 head,這個解法的時間複雜度是 O(n),因為要遍歷整個鏈結串列。

心得:對我來說,遇到的困難主要集中在怎麼正確地操作指針來交換節點,尤其是要避免指針錯亂或跟丟節點,因為鏈結串列涉及到多個節點的指向關係,一不小心就會讓程式無法正常工作,問題的關鍵是怎麼處理兩個相鄰節點的交換,交換節點時,不能只是簡單地調換節點的值,因為題目明確要求只交換節點本身,不修改節點的值,所以,要設計一個策略來更新節點間的指向。

其中一個挑戰是頭節點的交換,因為鏈結串列的頭節點可能會被替換,所以就要引入一個「虛擬節點」來指向原來的頭節點,這樣才能確保在進行頭節點交換時不會丟失對整個鏈結串列的控制。
然後是迭代處理的問題,每次交換兩個相鄰節點後,要正確地移動指針,才能繼續處理剩下的節點,如果指針移動不對,就無法處理所有節點,或造成節點丟失。
對於邊界條件的考慮也很重要,如果鏈結串列的節點數是奇數,那最後一個節點不能交換,這需要在程式中處理,還有,當鏈結串列為空或只有一個節點時,就直接返回原鏈結串列。

這題幫我更了解鏈結串列的基本操作,尤其是指針操作的細節,在解題過程,我學會怎麼透過引入「虛擬節點」來簡化操作,避免對頭節點進行特殊處理,這題也強調邊界條件處理的重要,讓我在之後寫程式時會更注重對特殊情況的考慮。


上一篇
D5:Q22Generate Parentheses
下一篇
D7:Q30Substring with Concatenation of All Words
系列文
Leecode刷題10
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言